package com.example.demo.core;

import com.example.demo.annotation.Collection;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.result.InsertOneResult;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;

@Component
public class MongoUtil {

    @Autowired
    MongoClient client;

    public <T> InsertOneResult insetOne(T document, Class<T> documentClass){
        MongoCollection<T> collection=this.getCollection(documentClass);
        InsertOneResult result= collection.insertOne(document);
        return result;
    }


    public <T> List<T> find(Bson document, Class<T> documentClass){
        MongoCollection<T> collection=this.getCollection(documentClass);
        List<T> list = new LinkedList<>();
        collection.find(document,documentClass).forEach(t -> list.add(t));
        return list;
    }

    public <T> List<T> find(Bson document, String collectionName, ResultMapper<T> mapper){
        MongoCollection<Document> collection=client.getDatabase("test").getCollection(collectionName);
        List<T> list = new LinkedList<>();
        collection.find(document).forEach(t -> list.add(mapper.map(t)));
        return list;
    }

    public <T> void findConsumer(Bson document, Class<T> documentClass, Consumer<T> consumer){
        MongoCollection<T> collection=this.getCollection(documentClass);
        collection.find(document,documentClass).forEach(consumer);
    }

    public <T> List<T> agg(List<? extends Bson> pipeline,String collectionName, Class<T> documentClass){
        MongoCollection<Document> collection=client.getDatabase("test").getCollection(collectionName);
        AggregateIterable<T> result= collection.aggregate(pipeline,documentClass);
        List<T> list = new LinkedList<>();
        result.forEach(t -> list.add(t));
        return list;
    }

    public Document agg(List<? extends Bson> pipeline,String collectionName){
        MongoCollection<Document> collection=client.getDatabase("test").getCollection(collectionName);
        AggregateIterable<Document> result= collection.aggregate(pipeline,Document.class);
        Document document = new Document();
        List<Document> list = new ArrayList<>();
        result.forEach(t -> list.add(t));
        document.append("result",list);
        return document;
    }

    public void drop(String collectionName){
        MongoCollection<Document> collection=client.getDatabase("test").getCollection(collectionName);
        collection.drop();
    }

    public <T> void drop(Class<T> documentClass){
        MongoCollection<T> collection=this.getCollection(documentClass);
        collection.drop();
    }

    private <T>  MongoCollection<T> getCollection(Class<T> documentClass){
        Collection collection1= documentClass.getAnnotation(Collection.class);
        String collectionName= documentClass.getSimpleName().toLowerCase();
        if (null != collection1){
            collectionName =collection1.name();
        }
        collectionName+="_client";
        MongoCollection<T> collection=client.getDatabase("test")
                .getCollection(collectionName,documentClass);
        return  collection;
    }
}
